package stone926.mods.more_enchantments.blocks;

import net.minecraft.block.*;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.boss.WitherEntity;
import net.minecraft.entity.boss.dragon.EnderDragonEntity;
import net.minecraft.entity.effect.StatusEffect;
import net.minecraft.entity.mob.HostileEntity;
import net.minecraft.entity.mob.Monster;
import net.minecraft.entity.passive.PassiveEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.FluidState;
import net.minecraft.fluid.Fluids;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.predicate.entity.EntityPredicates;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.state.StateManager;
import net.minecraft.state.property.BooleanProperty;
import net.minecraft.state.property.Properties;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.Difficulty;
import net.minecraft.world.World;
import net.minecraft.world.WorldAccess;
import net.minecraft.world.WorldView;
import net.minecraft.world.dimension.DimensionType;
import stone926.mods.more_enchantments.MoreEnchantmentsMod;
import stone926.mods.more_enchantments.damage.StoneDamageSource;
import stone926.mods.more_enchantments.enchantments.MandalaResistanceEnchantment;
import stone926.mods.more_enchantments.interfaces.IEntitySpawnedByFlower;
import stone926.mods.more_enchantments.mixins.accessors.EnderDragonFightAccessor;
import stone926.mods.more_enchantments.spawn.BlackMandalaSpawner;
import stone926.mods.more_enchantments.util.BlockUtil;
import stone926.mods.more_enchantments.util.EnchantmentUtil;
import stone926.mods.more_enchantments.util.RandomUtil;

import java.util.List;
import java.util.Random;

import static stone926.mods.more_enchantments.MoreEnchantmentsMod.*;

public class BlackMandalaFlowerBlock extends FlowerBlock implements Waterloggable {

  public static final BooleanProperty WATERLOGGED = Properties.WATERLOGGED;

  public BlackMandalaFlowerBlock(StatusEffect suspiciousStewEffect, int effectDuration, Settings settings) {
    super(suspiciousStewEffect, effectDuration, settings);
    this.setDefaultState(getDefaultState().with(WATERLOGGED, false));
  }

  @Override
  public void randomDisplayTick(BlockState state, World world, BlockPos pos, Random random) {
    super.randomDisplayTick(state, world, pos, random);
    RandomUtil.runIfPossible(0.1, random, () -> world.addParticle(ParticleTypes.WITCH, pos.getX() + 0.5, pos.getY() + 1, pos.getZ() + 0.5, 0, 1, 0));
  }

  @Override
  public void onEntityCollision(BlockState state, World world, BlockPos pos, Entity entity) {
    super.onEntityCollision(state, world, pos, entity);
    if (!(entity instanceof LivingEntity livingEntity) || !(world instanceof ServerWorld server)) return;

    int totalResistanceLvl = EnchantmentUtil.getTotalEquipmentLvl(MANDALA_RESISTANCE, livingEntity);
    if (totalResistanceLvl >= 12) return;

    int resistanceLvl = EnchantmentHelper.getEquipmentLevel(MANDALA_RESISTANCE, livingEntity);
    if (
      !((IEntitySpawnedByFlower) livingEntity).isSpawnedByMandala()
        && !(livingEntity instanceof Monster)
    ) {
      if (livingEntity.hasStatusEffect(MoreEnchantmentsMod.MEMORIAL_CEREMONY_EFFECT)) return;
      if (livingEntity instanceof PassiveEntity passiveEntity) {
        if (passiveEntity.damage(StoneDamageSource.BLACK_MANDALA, Integer.MAX_VALUE)) {
          trySpread(server, server.random, pos, state, false);
        }
      } else {
        if (
          livingEntity.damage(
            StoneDamageSource.BLACK_MANDALA,
            MandalaResistanceEnchantment.getDecreasedDamage(2F, resistanceLvl)
          ) && RandomUtil.isPossible(95, world.random)
        ) {
          trySpread(server, server.random, pos, state, false);
        }
      }
    } else {
      if (RandomUtil.isPossible(5, world.random)) livingEntity.heal(1);
    }

  }

  @Override
  public void randomTick(BlockState state, ServerWorld world, BlockPos pos, Random random) {
    super.randomTick(state, world, pos, random);
    if (RandomUtil.isPossible(0.4, random)) {
      List<LivingEntity> livingEntities = world
        .getEntitiesByClass(
          LivingEntity.class,
          Box.from(new Vec3d(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5)).expand(6),
          EntityPredicates.VALID_LIVING_ENTITY
        )
        .stream()
        .filter(l -> !(l instanceof WitherEntity) && !(l instanceof EnderDragonEntity))
        .filter(l -> !(l instanceof HostileEntity))
        .filter(l -> !(((IEntitySpawnedByFlower) l).isSpawnedByMandala()))
        .filter(l -> {
          int resistanceLvl = EnchantmentHelper.getEquipmentLevel(MANDALA_RESISTANCE, l);
          return resistanceLvl <= 0 || !RandomUtil.isPossible(MandalaResistanceEnchantment.getNotDrawProbability(resistanceLvl), world.random);
        })
        .filter(l -> !(l instanceof PlayerEntity p && p.isCreative() && p.getAbilities().flying))
        .toList();

      if (!livingEntities.isEmpty()) {
        world.spawnParticles(
          ParticleTypes.FALLING_OBSIDIAN_TEAR,
          pos.getX() + 0.5, pos.getY() + 4, pos.getZ() + 0.5,
          180, 0.1, 2, 0.1, 0
        );
        for (LivingEntity l : livingEntities) {
          int resistanceLvl = EnchantmentHelper.getEquipmentLevel(MANDALA_RESISTANCE, l);
          world.spawnParticles(
            ParticleTypes.WITCH,
            l.getX(), l.getY() + l.getEyeHeight(l.getPose()), l.getZ(),
            6, 0.1, 0.1, 0.1, 0.2F
          );
          double multiplier = 0.33;
          l.setVelocity(new Vec3d(
            (pos.getX() - l.getX()) * multiplier,
            (pos.getY() - l.getY()) * multiplier,
            (pos.getZ() - l.getZ()) * multiplier
          ));
          l.damage(
            StoneDamageSource.BLACK_MANDALA,
            MandalaResistanceEnchantment.getDecreasedDamage(3 + (
              l.hasStatusEffect(MoreEnchantmentsMod.MEMORIAL_CEREMONY_EFFECT) ?
                l.getStatusEffect(MoreEnchantmentsMod.MEMORIAL_CEREMONY_EFFECT).getAmplifier() + 5 : 0
            ), resistanceLvl)
          );
          l.removeStatusEffect(MoreEnchantmentsMod.MEMORIAL_CEREMONY_EFFECT);
        }
      }
    }

    if (world.getGameRules().getBoolean(BLACK_MANDALA_SPAWNING) && world.getDifficulty() != Difficulty.PEACEFUL) {
      DimensionType dimension = world.getDimension();
      int weather = 0;
      if (world.isThundering()) weather += 2;
      else if (world.isRaining()) weather++;
      boolean isDark = world.isNight() || dimension.hasFixedTime();
      int dragonFight = 0;
      EnderDragonFightAccessor enderDragonFight = (EnderDragonFightAccessor) world.getEnderDragonFight();
      if (world.getRegistryKey().equals(World.END)
        && enderDragonFight != null
        && !(enderDragonFight).isDragonKilled()
      ) {
        dragonFight = 2;
      }
      if (RandomUtil.isPossible(Math.max(1, (isDark ? (8 - weather) : (40 - weather)) - dragonFight), random)) {
        BlackMandalaSpawner.spawnMonster(world, pos, random, weather, isDark ? 5 : 0);
      }
    }

    if (RandomUtil.isPossible(37, random)) {
      trySpread(world, random, pos, state, RandomUtil.isPossible(0.9, random));
    }
  }

  private void trySpread(ServerWorld world, Random random, BlockPos pos, BlockState state, boolean b) {
    if (b) {
      int i = 4;
      for (BlockPos blockPos : BlockPos.iterate(pos.add(-3, -2, -3), pos.add(3, 2, 3))) {
        if (world.getBlockState(blockPos).isOf(this)) {
          --i;
          if (i <= 0) {
            return;
          }
        }
      }
    }
    ((Fertilizable) this).grow(world, random, pos, state);
  }

  @Override
  protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
    super.appendProperties(builder);
    builder.add(WATERLOGGED);
  }

  public BlockState getStateForNeighborUpdate(BlockState state, Direction direction, BlockState neighborState, WorldAccess world, BlockPos pos, BlockPos neighborPos) {
    if (state.get(WATERLOGGED)) {
      world.createAndScheduleFluidTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world));
    }
    return super.getStateForNeighborUpdate(state, direction, neighborState, world, pos, neighborPos);
  }

  public FluidState getFluidState(BlockState state) {
    return state.get(WATERLOGGED) ? Fluids.WATER.getStill(false) : super.getFluidState(state);
  }

  public BlockState getPlacementState(ItemPlacementContext ctx) {
    FluidState fluidState = ctx.getWorld().getFluidState(ctx.getBlockPos());
    return this.getDefaultState().with(WATERLOGGED, fluidState.getFluid() == Fluids.WATER);
  }

  @Override
  public boolean canPlaceAt(BlockState state, WorldView world, BlockPos pos) {
    return super.canPlaceAt(state, world, pos)
      || BlockUtil.mandalaAndCornelCanPlaceAt(state, world, pos)
      || state.isOf(CHRYSANTHEMUM);
  }

}
